from wydbus import WyDbus
#from wydbus import WDB_AS_THREAD
from wydbus import WDB_FREE_ARGS
from peewee.misc_utils import MetaSingleton
import datetime

# wyscan signal Errors type :
WY_UNDEFINED_ERROR=0

# wyscan signal Events type :
WY_UNDEFINED_EVENT=0
WY_SCAN_FINISHED=1
WY_NO_LOCK=2
WY_LOCK_OK=3

            
class WYScanServer:
    """
    callbacks methods for errorCallback and eventCallback 
    must have the following prototype: (type,message)
    
    message is a String
    type may have the following values:
    
        Errors type :
        WY_UNDEFINED_ERROR                0
    
        Events type :
        WY_UNDEFINED_EVENT                0
        WY_SCAN_FINISHED                  1
        WY_NO_LOCK                        2
        WY_LOCK_OK                        3
    """
    __metaclass__ = MetaSingleton
    def __init__(self, strBusName="com.wyplay.wyscan", 
                       strPathName="/com/wyplay/WyScan",
                       strWyDbusInstanceName="deprecated-argument"):

        #print "Init WyDbus for wyscan: "
        self.wdb = WyDbus()
        self.wdb_inst = self.wdb.instance(strPathName)
        self.ref = self.wdb.reference(strBusName, strPathName)

        # reference method for wyscan api
        self.com_test = self.ref.method("com_test", "", "b")
        self.signal_test = self.ref.method("signal_test", "", "")
        self.GetVersionNumber = self.ref.method("GetVersionNumber", "", "s")
        self.Version = self.ref.method("version", "", "s")
        self._GetTransponderSets = self.ref.method("GetTransponderSets", "ii", "a(isi)")
        self._GetTransponders = self.ref.method("GetTransponders", "ii", "a(issi)")
        self.SaveTransponder = self.ref.method("SaveTransponder", "iiss", "(ii)")
        self.RemoveTransponder = self.ref.method("RemoveTransponder", "i", "i")
        self._GetAntenna = self.ref.method("GetAntenna", "i", "a(isiiiiiiiii)")
        self._SaveAntenna = self.ref.method("SaveAntenna", "isiiiiiiiii", "i")
        self._GetLNBTypes = self.ref.method("GetLNBTypes",  "i", "a(isiiiii)")
        self.SaveLNBType = self.ref.method("SaveLNBType", "isiiii", "i")
        self.RemoveLNBType = self.ref.method("RemoveLNBType", "i", "i")
        self._GetFrontendState = self.ref.method("GetFrontendState", "i", "(iiiii)")
        self._Tune = self.ref.method("Tune", "iii", "i")
        #self.GetDVBTCountryList = self.ref.method("GetDVBTCountryList", "", "as")
        #self.GetDVBTCityList = self.ref.method("GetDVBTCityList", "s", "as")
        #self.GetDVBTTransponderSetID = self.ref.method("GetDVBTTransponderSetID", "ss", "i")
        self._StartScan = self.ref.method("StartScan", "iiiibb", "i")
        self.StopScan = self.ref.method("StopScan",  "i", "i")
        self.CommitScan = self.ref.method("CommitScan", "i", "i")
        self.GetCommitScanProgress = self.ref.method("GetCommitScanProgress", "i", "(iii)")
        self.RollbackScan = self.ref.method("RollbackScan", "i", "i")
        self.GetScanStatus = self.ref.method("GetScanStatus",  "i", "(iiiiiiiiii)")
        self._GetScanServiceList = self.ref.method("GetScanServiceList", "i", "(iat)")
        self.RemoveService = self.ref.method("RemoveService", "i", "i")
        self._SaveService = self.ref.method("SaveService", "tisssi", "(it)")
        self.GetServiceDevices = self.ref.method("GetServiceDevices", "t", "a(isiissii)")
        self._GetServicesByName = self.ref.method("GetServicesByName", "si", "(ia(tissiiiiiiia(iis)))")
        self._GetServices = self.ref.method("GetServices", "iii", "(ia(tissiiiiiiia(iis)))")
        self._GetService = self.ref.method("GetService", "t", "(ia(tissiiiiiiia(iis)))")
        self.GetChannelList = self.ref.method("GetChannelList", "", "a(tsiii)")
        self._GetDevices = self.ref.method("GetDevices", "ii", "a(isiissii)")
        self.UpdateDevice = self.ref.method("UpdateDevice", "iii", "i")
        self.GetDevicesByName = self.ref.method("GetDevicesByName", "s", "a(isiissii)")
        self.ResetDatabase = self.ref.method("ResetDatabase", "", "i")
        self._EPG_GetServiceInstantPrograms = self.ref.method("EPG_GetServiceInstantPrograms", "itsi", "(ia(ttiia(ssssi)))")
        self._Capture_GetInputs = self.ref.method("Capture_GetInputs", "i", "(ias)")
        self._Capture_GetInputStandards = self.ref.method("Capture_GetInputStandards", "is", "(ias)")
        self._Capture_GetAspectRatios = self.ref.method("Capture_GetAspectRatios", "i", "(ias)")
        self._Capture_GetCaptureProperties = self.ref.method("Capture_GetCaptureProperties", "ii", "(is)")
        self._Capture_SetCaptureProperties = self.ref.method("Capture_SetCaptureProperties", "iis", "i")
        self._Record_StartRecording = self.ref.method("Record_StartRecording", "itssii", "(iii)")
        self._Record_Zap = self.ref.method("Record_Zap", "iitssii", "(iii)")
        self.Record_StopRecording = self.ref.method("Record_StopRecording", "i", "i")
        self.Record_SwitchRecording = self.ref.method("Record_SwitchRecording", "ii", "i")
        self._Record_StartInstantRecord = self.ref.method("Record_StartInstantRecord", "iss", "i")
        self._Record_StopInstantRecord = self.ref.method("Record_StopInstantRecord", "is", "i")
        self._Record_StopDeviceRecordings = self.ref.method("Record_StopDeviceRecordings", "i", "i")
        self._Record_AreServicesCompatible = self.ref.method("Record_AreServicesCompatible", "itit", "i")
        self._DateTime_UTC2Text = self.ref.method("DateTime_UTC2Text", "is", "s")
        self._DateTime_Text2UTC = self.ref.method("DateTime_Text2UTC", "ss", "i")
        self._DateTime_GetCurrentUTCTime = self.ref.method("DateTime_GetCurrentUTCTime", "", "i")
        self._Device_GetTime = self.ref.method("Device_GetTime", "i", "i")
        #self._Tools_GetChunkFileIndex = self.ref.method("Tools_GetChunkFileIndex", "ss", "(ii)")
        self.StopServer = self.ref.method("StopServer", "", "")
        self.RemoveAllServices = self.ref.method("RemoveAllServices", "", "i")
        self.startExternEIT = self.ref.method("startExternEIT", "st", "b")
        self.stopExternEIT = self.ref.method("stopExternEIT", "i", "b")
        self._EPGFromProgramId = self.ref.method("EPGFromProgramId", "t", "(yttiiissssiiiiiiiiii)")
        self._EPGFromServiceIDEndStartTime = self.ref.method("EPGFromServiceIDEndStartTime", "tii", "aa{ss}")
        #self.InitExternEITFromDBOnLive = self.ref.method("InitExternEITFromDBOnLive", "sit", "b")
        self.EnableHighLnbVoltage = self.ref.method("EnableHighLnbVoltage", "ib", "b")
        self.SetIso639LanguageCode = self.ref.method("SetIso639LanguageCode", "s", "b")
        self.SetIso3166CountryCode = self.ref.method("SetIso3166CountryCode", "s", "b")
        self.LeaveDeviceDvr = self.ref.method("LeaveDeviceDvr", "i", "i")
        self.RemoveExtraPIDs = self.ref.method("RemoveExtraPIDs", "i", "i")
        self.AppendNewExtraPID = self.ref.method("AppendNewExtraPID", "ii", "i")
        self.StartParralelRecoder = self.ref.method("StartParralelRecoder", "is", "b")
        self.StopParralelRecoder = self.ref.method("StopParralelRecoder", "i", "b")
        self.ConfigurePermanentScan = self.ref.method("ConfigurePermanentScan", "bb", "")        
        
        
        
        #{ "test", { "s", "s" }, (void (*) ())test},
        #{ "SetVideoWindow", { "iiii", "" }, (void (*) ())SetVideoWindow}, //obsolete
        #{ "StopServer", { "", "" }, (void (*) ())StopServer},
        #{ "SetProtectionMode", { "i", "i" }, (void (*) ())SetProtectionMode}, //obsolete
        #{ "GetProtectionMode", { "", "i" }, (void (*) ())GetProtectionMode}, //obsolete
        #{ "CreateFavoriteSet", { "sss", "i" }, (void (*) ())CreateFavoriteSet}, //obsolete
        #{ "RemoveFavoriteSet", { "i", "i" }, (void (*) ())RemoveFavoriteSet}, //obsolete
        #{ "StartLive", { "ii", "i" }, (void (*) ())StartLive}, //obsolete
        #{ "StopLive", { "i", "i" }, (void (*) ())StopLive}, //obsolete



        # build the two callback server
        self.errorCallback = CallbackServer()
        self.eventCallback = CallbackServer()
        self.epgCallback = CallbackServer()
        self.newEpgAvailableCallback = CallbackServer()
        self.newExternEpgAvailableCallback = CallbackServer()
        self.scanEventCallback = CallbackServer()
        self.serviceUpdateCallback = CallbackServer()
        self.deviceSignalCallback = CallbackServer()
        self.pmtUpdatedCallback = CallbackServer()
        self.patUpdatedCallback = CallbackServer()
        self.scanProgression = CallbackServer()
        self.macrovision = CallbackServer()
        #self.setTimeCallback = CallbackServer()
    
        self.wdb_callback = WyDbus(strWyDbusInstanceName + ".callback")
        self.wdb_inst_callback = self.wdb_callback.instance(strPathName)
        # connect callbacks to dbus
        self.wdb_inst_callback.signal("Error", "is", self.errorCallback.notify, 0)
        self.wdb_inst_callback.signal("Event", "is", self.eventCallback.notify, 0)
        self.wdb_inst_callback.signal("EPG", "(yttiiissssi)", self.epgCallback.notify, 0)
        self.wdb_inst_callback.signal("NewExternEPGAvailable", "(yttiiissssiiiiiiiiii)s", self.__newExternEpgAvailableCallback, 0)
        self.wdb_inst_callback.signal("NewEPGAvailable", "tti", self.newEpgAvailableCallback.notify, 0)
        self.wdb_inst_callback.signal("ScanEvent", "ii", self.scanEventCallback.notify, 0)
        self.wdb_inst_callback.signal("ServiceUpdate", "ia(tsiii)(iii)", self.serviceUpdateCallback.notify, 0)
        self.wdb_inst_callback.signal("DeviceSignal", "ib", self.deviceSignalCallback.notify, 0)
        self.wdb_inst_callback.signal("PmtUpdated", "", self.pmtUpdatedCallback.notify, 0)
        self.wdb_inst_callback.signal("PatUpdated", "", self.patUpdatedCallback.notify, 0)
        self.wdb_inst_callback.signal("ScanProgression", "iiii", self.scanProgression.notify, 0)
        self.wdb_inst_callback.signal("MacrovisionSignal", "ti", self.macrovision.notify, 0)
        
        #self.wdb_inst.signal("set_time", "(xx)", self.setTimeCallback.notify, WDB_AS_THREAD)
    
    def GetTransponderSets(self, nTransponderSetID = -1, nTransponderType = 0):
        """
        nTransponderType => 0 : All types of transponders
                 => 1 : DVB-T transponders
                 => 2 : DVB-S transponders
                 => 4 : DVB-C transponders
        result:
           result[i][0] = TransponderSet ID (i4)
           result[i][1] = TransponderSet Name (string)
           result[i][2] = TransponderSet Type (i4)
        """
        return self._GetTransponderSets(nTransponderSetID, nTransponderType)
        
    def GetFEState(self, nDeviceID):
        result = list (self._GetFrontendState(nDeviceID))
        if len(result) == 0:
            return None
                
        if result[0] <> 0:
            return None
        
        if result[1] == 0:
            result[1] = False
        else:
            result[1] = True
        
        # result[0] : 0
        # result[1] : locked/not locked
        # result[2] : SignalToNoiseRatio
        # result[3] : SignalStrength
        # result[4] : Adapter Type
        #        => 0 : Unknown
        #        => 1 : DVB-S
        #        => 2 : DVB-T
        #        => 3 : DVB-C
        #        => 4 : ATSC
        #        => 5 : Analog
        return result

#    def GetDVBTCountryList(self):
#        return self._GetDVBTCountryList()
#    def GetDVBTCityList(self, strCountryID):
#        return self._GetDVBTCityList(strCountryID)
#    def GetDVBTTransponderSetID(self, strCountryID, strCity):
#        return self._GetDVBTTransponderSetID(strCountryID, strCity)
    def GetTranspondersEx(self, TransponderSetID, TransponderID = -1):
        res = self.GetTransponders(TransponderSetID, TransponderID)
        tplist = {}
        for restp in res:
            tplist[restp[0]] = Transponder(restp)
        return tplist
    def GetTransponders(self, TransponderSetID, TransponderID = -1):
        return self._GetTransponders(TransponderSetID, TransponderID)
    def Tune(self, nDeviceID, transponderID, timeout=0):
        res = self._Tune(nDeviceID, transponderID, timeout)
#        if res[0] == 0:
#            if res[1] == 0:
#                return False
#            else:
#                return True
        return res == 0
    def StartScan(self, nDeviceID, nTransponderSetID, nTransponderID = -1, nScanNetwork = 0, bWithScrambled=True, bWithRadio=False):
        return self._StartScan(nDeviceID, nTransponderSetID, nTransponderID, nScanNetwork, bWithScrambled, bWithRadio)
#    def StopScan(self, nDeviceID):
#        return self._StopScan(nDeviceID)
    
#    def GetScanStatus(self, nDeviceID):
#        """
#        Result:
#        [0] = call result (0 : OK, <>0 => Error)
#        [1] = State :
#                0 : Stopped
#            1 : Starting
#            2 : Running
#            3 : Stopping
#        [2] = Progress
#        [3] = Progress Max value
#        """
#        return self._GetScanStatus(nDeviceID)

    def GetScanServices(self, nDeviceID):
        """
        Result:
        [0] = call result (0 : OK, <>0 => Error)
        [1] = Array of Service IDs (ints)
        """
        return self._GetScanServiceList(nDeviceID)
    def GetService(self, nService_ID, nFormat = 0):
        """
        Result:
        [0] = call result (0 : OK, <>0 => Error)
        [1] = Array of Service properties
        if Format == 0:
           result[1][0][0] = Service ID
           result[1][0][1] = Transponder ID
           result[1][0][2] = Service Name
           result[1][0][3] = Service Type
        """
        return self._GetService(nService_ID)
    def GetServices(self, nTransponderSetID, nTransponderID = -1, nServiceType = 1, nFormat = 0):
        """
        Result:
        [0] = call result (0 : OK, <>0 => Error)
        [1] = Array of Service properties
        if Format == 0:
           result[1][n][0] = Service ID
           result[1][n][1] = Transponder ID
           result[1][n][2] = Service Name
           result[1][n][3] = Service Type
           result[1][n][4] = Protected (0 = No, 1 = yes)
        if Format == 1 (Semi-detailed format):
           result[1][n][0] = ServiceID (i4)
           result[1][n][1] = TransponderID (i4)
           result[1][n][2] = ServiceName (string)
           result[1][n][3] = ProviderName (string)
           result[1][n][4] = Properties (string)
           result[1][n][5] = DVBServiceID (i4)
           result[1][n][6] = NetworkID (i4)
           result[1][n][7] = TransportStreamID (i4)
           result[1][n][8] = Protected (0 = No, 1 = yes)
        if Format == 2 (Detailed format):
           result[1][n][0] = ServiceID (i4)
           result[1][n][1] = TransponderID (i4)
           result[1][n][2] = ServiceName (string)
           result[1][n][3] = ProviderName (string)
           result[1][n][4] = ServiceType (i4)
                    => 0 : Unknown
                    => 1 : Radio
                    => 2 : TV
                    => 3 : Data
           result[1][n][5] = VideoPID (i4)
           result[1][n][6] = PCRPID (i4)
           result[1][n][7] = PMTPID (i4)
           result[1][n][8] = TeletextPID (i4)
           result[1][n][9] = Scrambled (i4) (0 : Not scrambled, 1 : scrambled)
           result[1][n][10] = Protected (0 = No, 1 = yes)
           result[1][n][11] = Array of AudioStreams
                {
                    PID (i4)
                    Type (i4)
                        => 0 : Unknown
                        => 1 : MPEG2
                        => 2 : AC3
                    Language (string)
                }
        Service Properties:
        # SID:NID:TID:VPID:PCRPID:AudioStreams:PMTPID:TPID:SBPID
        # Each numeric value is specified in decimal
        # Each of those fields can be empty (0 values)
        # SID : Service ID
        # NID : Network ID
        # TID : Transport Stream ID
        # VPID : Video PID
        # PCRPID : PCR PID
        # AudioStreams : List of Audio stream strings separated by ',' character (see CDVBAudioStream class)
        # PMTPID: PMT PID
        # TPID : Teletext PID
        # SBPID: Subtitling PID
        """
        return self._GetServices(nTransponderSetID, nTransponderID, nServiceType)
    
    def GetServicesByName(self, strServiceName, nServiceType = 2, nFormat = 0):
        """
        Result:
        [0] = call result (0 : OK, <>0 => Error)
        [1] = Array of Service properties
        if Format == 0:
           result[1][0][0] = Service ID
           result[1][0][1] = Transponder ID
           result[1][0][2] = Service Name
           result[1][0][3] = Service Type
        """
        return self._GetServicesByName(strServiceName, nServiceType)
    
    def GetAntenna(self, nAntennaID = -1):
        """
        Result Array of Antennas:
        [i][0] = ID
        [i][1] = Name
        [i][2] = Switch Type
                => 0 : None
                => 1 : ToneBurst
                => 2 : DiSEqC 1.0
        [i][3] = Switch Position
        [i][4] = LNB Power
                => 0 : OFF
                => 1 : ON
        [i][5] = LNB Type ID
        [i][6] = Transponder Set ID
        [i][7] = Device ID
        [i][8] = Motor Position
        [i][9] = Motor Limit Low
        [i][10] = Motor Limit High
        """
        return self._GetAntenna(nAntennaID)
    
    def SaveAntenna(self, id, name, switchtype, switchport, lnbpower,lnbtypeid, transpondersetid, deviceid, motorposition=0, motorlimitlow=0, motorlimithigh=0):
        return self._SaveAntenna(id, name, switchtype, switchport, lnbpower,lnbtypeid,transpondersetid, deviceid, motorposition, motorlimitlow, motorlimithigh)
#    def SaveLNBType(self, id, name, freq_low, freq_high, freq_switch, tone):
#        return self._SaveLNBType(id, name, int(freq_low), int(freq_high), int(freq_switch), tone)
    
#    def SaveTransponder(self, transponderid, transpondersetid, name, properties):
#        """
#            SaveTransponder:
#            Name : SaveTransponder
#            Param IN:
#                    Transponder ID (i4)
#                            => < 0 : A new transponder will be added
#                            => >= 0 : The existing transponder is updated
#                    TransponderSet ID (i4) (must be valid if Transponder ID < 0 !)
#                    TransponderName (string)
#                    Properties (string) (see description above)
#            Param OUT:
#                    Result (i4)
#                        => WY_ERROR_SUCCESS : OK
#                        => WY_ERROR_FAILED : NOK
#                        => WY_ERROR_BAD_TRANSPONDER_ID : Bad transponder ID
#                        => WY_ERROR_BAD_TRANSPONDER_SET_ID : Bad transponder set ID
#                        => WY_ERROR_BAD_PROPERTIES
#                        => WY_ERROR_SAVE_FAILED
#                    if Result == WY_ERROR_SUCCESS:
#                        Transponder ID (i4)
#        """
#        return self._SaveTransponder(transponderid, int(transpondersetid), str(name), str(properties))
    def SaveService(self, id, transponderid, name, provider, properties, protected=0):
        return self._SaveService(id, transponderid, name, provider, properties, protected)

#    def RemoveTransponder(self, transponderid):
#        return self._RemoveTransponder(transponderid)

#    def RemoveService(self, id):
#        return self._RemoveService(id)

    def GetLNBTypes(self, nLNBTypeID = -1):
        """
        Result Array of LNB Types:
        [i][0] = ID
        [i][1] = Name
        [i][2] = ReadOnly
        [i][3] = Frequency Low
        [i][4] = Frequency High
        [i][5] = Frequency Switch
        [i][6] = 22KHz Tone
            => 0 : OFF
            => 1 : ON
            => 1 : AUTO
        """
        return self._GetLNBTypes(nLNBTypeID)
    
    def GetFrontendState(self, nDeviceID = 0):
        """
        Result Array of LNB Types:
        [0] = result
        [1] = locked (0/1)
        [2] = Signal to noise ratio
        [3] = Signal strength
        [4] = Frontend type
            => 0 : Unknown
            => 1 : DVB-S
            => 2 : DVB-T
            => 3 : DVB-C
            => 4 : ATSC
            => 5 : Analog
        """
        return self._GetFrontendState(nDeviceID)

    def GetDevicesEx(self, nDeviceID = -1, nDeviceType = -1):
        """
        Return an array of Device objects
        """
        result = self.GetDevices(nDeviceID, nDeviceType)
        devices = []
        for deviceargs in result:
            devices.append(Device(deviceargs))
        return devices
    
    def GetDevices(self, nDeviceID = -1, nDeviceType = -1):
        """
        nDeviceID = -1 => All Devices
        nDeviceType :
            => -1 : All Type of Devices
            => 1 : DVB-T
            => 2 : DVB-S
            => 4 : DVB-C
            => 8 : ATSC
            => 16 : Analog Acquisition (Capture) device
        Result: Array of Devices
           result[i][0] = DeviceID
           result[i][1] = Name
           result[i][2] = Type (same as nDeviceType)
           result[i][3] = Position
           result[i][4] = Frontend device name (ex: /dev/dvb/adapter0/frontend0)
           result[i][5] = Demux device name
           result[i][6] = Primary device ID
           result[i][7] = Priority
        """
        return self._GetDevices(nDeviceID, nDeviceType)
        
#    def GetDevicesByName(self, strDeviceName):
#        """
#        Result: Array of Devices
#           result[i][0] = DeviceID
#           result[i][1] = Name
#           result[i][2] = Type (same as nDeviceType)
#           result[i][3] = Position
#           result[i][4] = Frontend device name (ex: /dev/dvb/adapter0/frontend0)
#           result[i][5] = Demux device name
#           result[i][6] = Primary device ID
#           result[i][7] = Priority
#        """
#        return self._GetDevicesByName(strDeviceName)
#        
#    def GetServiceDevices(self, nServiceID):
#        """
#        Result: Array of Devices
#           result[i][0] = DeviceID
#           result[i][1] = Name
#           result[i][2] = Type (same as nDeviceType)
#           result[i][3] = Position
#           result[i][4] = Frontend device name (ex: /dev/dvb/adapter0/frontend0)
#           result[i][5] = Demux device name
#           result[i][6] = Primary device ID
#           result[i][7] = Priority
#        return self._GetDevices(nDeviceID, nDeviceType)
#        """
#        #dbus.UInt64(nServiceID)
#        return self._GetServiceDevices(nServiceID)
        
#    def UpdateDevice(self, nDeviceID, nPrimaryDeviceID, nPriority):
#        """
#        Result: 0 == Successful
#        """
#        return self._UpdateDevice(nDeviceID, nPrimaryDeviceID, nPriority)
        
#    def ResetDatabase(self):
#        return self._ResetDatabase()


    def EPG_GetServiceInstantPrograms(self, nDeviceID, nServiceID, strLanguage="", nFormat = 0):
        """
        IN :
           nServiceID : Database Service ID
           strLanguage : Language (if "" => All available languages are returned)
           nFormat : Format (0:Simple, 1:Detailed)
        Result:
           if result[0] == 0 => ok
           result[1] = array of Programs
              program[0] = Program ID
              program[1] = Service ID
              program[2] = Start time
              program[3] = Stop time
              program[4] = Array of program details
                  ProgramDetails[0] = Language
                  ProgramDetails[1] = Title
                  ProgramDetails[2] = ShortDescription
                  ProgramDetails[3] = Description
                  ProgramDetails[4] = Minimum age
                  ProgramDetails[5] = Array of program detail items (if Format = 1)
                  ProgramDetailItem[0] = Title
                  ProgramDetailItem[1] = Text
        """
        return self._EPG_GetServiceInstantPrograms(nDeviceID, nServiceID, strLanguage, nFormat)

#    def EPG_CleanUp(self, nMaximumStopTime):
#        """
#        if nMaximumStopTime == 0: ALl programs are removed
#        """
#        return self.server.EPG.CleanUp(nMaximumStopTime)

    def Capture_GetInputs(self, deviceid):
        """
        """
        res = self._Capture_GetInputs(deviceid)
        if res[0] != 0:
            return []
        return res[1]

    def Capture_GetInputStandards(self, deviceid, strInputName):
        """
        """
        res = self._Capture_GetInputStandards(deviceid, strInputName)
        if res[0] != 0:
            return []
        return res[1]

    def Capture_GetAspectRatios(self, deviceid):
        """
        """
        res = self._Capture_GetAspectRatios(deviceid)
        if res[0] != 0:
            return []
        return res[1]

    def Capture_GetCaptureProperties(self, deviceid, nCaptureType):
        """
        Param IN:
           Device ID (i4)
           Capture type (i4)
            => 0 : Video Capture
            => 1 : Audio Capture
        Result:
           Capture properties string
           => Format is the following:
           
            AC 'Input' VideoStandard ImageWidthxImageHeight AudioBitRate VideoBitRate MaxVideoBitRate VariableBitRate VideoAspect PMT_PID VIDEO_PID AUDIO_PID PCR_PID

            Where:

            Input: (Use Capture_GetInputs() to retrieve the list supported inputs)
            VideoStandard: (Use Capture_GetInputStandard() to retrieve the list supported standards)
            ImageWidthxImageHeight:
                Example : 720x576
            AudioBitRate: bit rate in Kbit/s
            VideoBitRate: Average bit rate in Kbit/s
            MaxVideoBitRate: Max bit rate in Kbit/s (useful if variable video bit rate)
            VariableBitRate:
                VBR or YES => Video bit rate is variable
                CBR or NO or else.. => Video bit rate is constant
            VideoAspect: (Use Capture_GetAspectRatios() to retrieve the list supported aspect ratios)
                SQUARE => Square pixel
                4/3    =>  4 : 3
                16/9   => 16 : 9
                1/221  =>  1 : 2.21
            Example : AC 'Front Y/C' PAL_BG 720x576 384 4000 6000 VBR 4/3 256 168 138 168
        """
        res = self._Capture_GetCaptureProperties(deviceid, nCaptureType)
        if res[0] != 0:
            return ""
        return res[1]

    def Capture_SetCaptureProperties(self, deviceid, nCaptureType, strCapturePropertiesString):
        """
        Param IN:
           Device ID (i4)
           Capture type (i4)
            => 0 : Video Capture
            => 1 : Audio Capture
           Capture properties string
                => Format (see Capture_GetCaptureProperties() method)
        Result:
        """
        res = self._Capture_SetCaptureProperties(deviceid, nCaptureType, strCapturePropertiesString)
        if res != 0:
            return False
        return True

    def Record_StartRecording(self, deviceid, serviceid, strName, strParameters, nRecordingType=2, bTryOtherDevices=False):
        """
        result: RecordingID
        """
        result = self.Record_StartRecordingEx(deviceid, serviceid, strName, strParameters, nRecordingType, bTryOtherDevices)
        if result[0] != 0:
            return 0
        return result[1]
    
    def Record_ZapEx(self, stopserviceid, deviceid, serviceid, strName, strParameters, nRecordingType=2, bTryOtherDevices=False):
        nTryOtherDevices = 0
        if bTryOtherDevices:
            nTryOtherDevices=1
        result = self._Record_Zap(stopserviceid, deviceid, serviceid, strName, strParameters, nRecordingType, nTryOtherDevices)
        return result

    
    def Record_StartRecordingEx(self, deviceid, serviceid, strName, strParameters, nRecordingType=2, bTryOtherDevices=False):
        """
        Param IN:
                deviceid : if 0 => Try all possible devices
            nRecordingType : 
               1 => Timeshift live
               2 => Normal live
               3 => Normal record
            strParameters : Depends on RecordingType
                RecordingType == 1 (timeshift live)
                    => timeshift_folder    :    Path to timeshift folder (mandatory)
                    => max_chunk_size    :    Max chunk size    (mandatory)
                    Example:
                        Parameters : timeshift_folder='/tmp/timeshift/ts1';'max_chunk_size=10000000'
                RecordingType == 2 (normal live)
                    => unix_socket_path    :    Unix socket full path name (mandatory)
                    => reuse : 0 or 1 (default is 1, optional)
                    Example:
                        Parameters : unix_socket_path='/tmp/mysock'
                RecordingType == 3 (normal record)
                    => file    :    Full file path name (mandatory)
        result:
           [ Status, RecordingID, DeviceID ]
        """
        nTryOtherDevices = 0
        if bTryOtherDevices:
            nTryOtherDevices=1
        result = self._Record_StartRecording(deviceid, serviceid, strName, strParameters, nRecordingType, nTryOtherDevices)
        return result

#    def Record_StopRecording(self, recordingid):
#        """
#        result:
#           if result[0] == 0 => ok
#           result[1] = Recording ID
#        """
#        return self._Record_StopRecording(recordingid)

#    def Record_SwitchRecording(self, nRecordingID, nRecordingSwitchType):
#        """
#        nRecordingSwitchType = 1 => Timeshift + Live
#        nRecordingSwitchType = 2 => Live
#        result:
#           if result == 0 => ok
#        """
#        return self._Record_SwitchRecording(nRecordingID, nRecordingSwitchType)

    def Record_StartInstantRecord(self, nRecordingID, strNewFilePathName, strFirstFilePathName = ""):
        """
        result:
           if result == 0 => ok
        """
        return self._Record_StartInstantRecord(nRecordingID, strNewFilePathName, strFirstFilePathName)

    def Record_StopInstantRecord(self, nRecordingID, strLastFilePathName = ""):
        """
        result:
           if result == 0 => ok
        """
        return self._Record_StopInstantRecord(nRecordingID, strLastFilePathName)

    def Record_StopDeviceRecordings(self, nDeviceID = 0):
        """
        result:
           if result == 0 => ok
        """
        return self._Record_StopDeviceRecordings(nDeviceID)

    def GetErrorString(self, nErrorNumber):
        return self._GetErrorString(nErrorNumber)

#    def Record_GetRecordingDetails(self, nRecordingID):
#        """
#        result:
#           if result[0] == 0 => ok
#                     => result[1] = array of the recording's properties
#        """
#        result = self.server.Record_GetRecordingDetails(nRecordingID)
#        if result[0] == 0:
#            return result[1]
#        return []
#
#    def Record_GetDeviceRecordings(self, nDeviceID = 0):
#        """
#        result:
#           if result[0] == 0 => ok
#                     => result[1] = array of arrays of recording's properties
#        """
#        result = self.server.Record.GetDeviceRecordings(nDeviceID)
#        if result[0] == 0:
#            return result[1]
#        return []

    def Record_AreServicesCompatible(self, nDeviceID1, nServiceID1, nDeviceID2, nServiceID2):
        """
        result:
           result == 0 => ok
        """
        return self._Record_AreServicesCompatible(nDeviceID1, nServiceID1, nDeviceID2, nServiceID2)

    def DateTime_UTC2Text(self, nUTCDateTime, strTextFormat = ""):
        """
        if strTextFormat == "" => %d/%m/%Y %H:%M:%S format is used
        result:
           result == "" => NOK
        """
        #return datetime.datetime.fromtimestamp(nUTCDateTime).strftime("%d/%m/%Y %H:%M:%S")
        return self._DateTime_UTC2Text(nUTCDateTime, strTextFormat)

    def DateTime_Text2UTC(self, strDateTimeText, strTextFormat = ""):
        """
        if strTextFormat == "" => %d/%m/%Y %H:%M:%S format is used
        result:
           result == 0 => NOK
                  != 0 => UTC Time
        """
        return self._DateTime_Text2UTC(strDateTimeText, strTextFormat)

    def DateTime_GetCurrentUTCTime(self):
        """
        result:
           result == 0 => NOK
                  != 0 => UTC Time
        """
        return self._DateTime_GetCurrentUTCTime()

    def Device_GetTime(self, nDeviceID):
        """
        result:
           result == 0 => NOK
                  != 0 => UTC Time
        """
        return self._Device_GetTime(nDeviceID)

    # associated pygui code:
    # /usr/lib/python2.5/site-packages/pygui/item/mediaitem/tv.py
    # def scrape_database(self, start_time, end_time, limit):                                                                  
    #     return WyRecord().wyscan.EPGFromServiceIDEndStartTime(int(self.wymedia_resource["serviceId"]), int(start_time), int(end_time))
    def EPGFromServiceIDEndStartTime(self, service_id, end_after_time, start_before_time):
        epg_list = self._EPGFromServiceIDEndStartTime(service_id, end_after_time, start_before_time)
        if epg_list:
            for epg in epg_list:
                epg["class"] = "object.item.epgItem"
        return epg_list

    def EPGFromProgramId (self, program_id):
        epg = self._EPGFromProgramId (program_id)
        return {'id':epg[1],
                'channelID':epg[2],
                'scheduledStartTime':epg[3],
                'scheduledEndTime':epg[4],
                'title':epg[6],
                'description':epg[7],
                'longDescription':epg[8],
                'language':epg[9], 
                'nrSubtitleTracks':epg[11], 
                'audioVisuallyImpaired':epg[12], 
                'nrAudioChannels':epg[13], 
                'contentDesc':epg[14], 
                'freeCaMode':epg[15], 
                'videoFormat_16_9':epg[16], 
                'videoFormatHD':epg[17], 
                'maturityRating':epg[10],
                'audioHardOfHearing':epg[18], 
                'subtitleHardOfHearing':epg[19] 
                }
    
    def __newExternEpgAvailableCallback(self, epg, path):
        epg_dict ={'id':epg[1],
                'channelID':epg[2],
                'scheduledStartTime':epg[3],
                'scheduledEndTime':epg[4],
                'title':epg[6],
                'description':epg[7],
                'longDescription':epg[8],
                'language':epg[9], 
                'nrSubtitleTracks':epg[11], 
                'audioVisuallyImpaired':epg[12], 
                'nrAudioChannels':epg[13], 
                'contentDesc':epg[14], 
                'freeCaMode':epg[15], 
                'videoFormat_16_9':epg[16], 
                'videoFormatHD':epg[17], 
                'maturityRating':epg[10],
                'audioHardOfHearing':epg[18], 
                'subtitleHardOfHearing':epg[19] 
                }
        self.newExternEpgAvailableCallback.notify(epg_dict, path)
#    //dbus signature: (yttiiissssi)
#    typedef struct {
#    uint8_t type;0
#    uint64_t program_id;1
#    uint64_t channel_id;2
#       int start_time;3
#       int stop_time;4
#       int event_id;5
#    char* name;6
#    char* desc;7
#    char* long_desc;8
#    char* language;9
#    
#    int minimum_age;    
#} EPG_t;



#    def SaveFavoriteSets(self, nFormat, nFavoriteSets):
#        """
#        favoriteset = nFavoriteSets[i]
#        favoriteset[0][0] = FavoriteSet ID
#        favoriteset[0][1] = Name
#        favoriteset[0][2] = Param 1
#        favoriteset[0][3] = Param 2
#        If nFormat == 1:
#           favorites = favoriteset[1]
#           favorites[n][0] = Favorite ID
#           favorites[n][1] = Service ID
#        """
#        return self.server.SaveFavoriteSets(nFormat, nFavoriteSets)

#    def GetFavoriteSets(self, nFavoriteSets = -1, nFormat = 0):
#        """
#        result: array of favoriteSets
#        favoriteset = result[i]
#        favoriteset[0][0] = FavoriteSet ID
#        favoriteset[0][1] = Name
#        favoriteset[0][2] = Param 1
#        favoriteset[0][3] = Param 2
#        If nFormat == 1:
#           favorites = favoriteset[1]
#           favorites[n][0] = Favorite ID
#           favorites[n][1] = Service ID
#        """
#        return self.server.GetFavoriteSets(nFavoriteSets, nFormat)

#    def CreateFavoriteSet(self, strName, strParam1, strParam2):
#        """
#        result: 
#        result[0] : Status (== 0 => OK!!)
#        result[1] : New favoriteSet ID !
#        """
#        return self.server.CreateFavoriteSet(strName, strParam1, strParam2)

#    def RemoveFavoriteSet(self, nFavoriteSetID):
#        """
#        result == 0 => OK !!! 
#        """
#        return self.server.RemoveFavoriteSet(nFavoriteSetID)

#    def SetProtectionMode(self, nProtectionMode):
#        """
#        nProtectionMode = 0 => Non protected mode
#        nProtectionMode = 1 => Protected mode
#        result == 0 => OK !!! 
#        """
#        return self.server.SetProtectionMode(nProtectionMode)
#
#    def GetProtectionMode(self):
#        """
#        result = 0 => Non protected mode
#        result = 1 => Protected mode
#        """
#        return self.server.GetProtectionMode()
#    def GetFavoriteServices(self, nFavoriteSetID, nFavoriteID, nServiceType=3, nFormat=0):
#        """
#        nServiceType :
#           1 = Radio
#           2 = TV
#           3 = Radio & TV
#        return : Array of services (same result as GetServices function)
#        """
#        return self.server.GetFavoriteServices(nFavoriteSetID, nFavoriteID, nServiceType, nFormat)
#
#    def GetEPGGrabStatus(self, nDeviceID):
#        """
#        if result[0] == 0:
#           result[1] = status:
#              => 0 = STOPPED
#                 1 = STARTING
#             2 = RUNNING
#             3 = STOPPING
#        """
#        return self.server.GetEPGGrabStatus(nDeviceID)
#
#    def StartEPGGrab(self, nDeviceID, nGrabDurationMilliseconds=3000, nLimitDate=-1):
#        """
#        result[0] == 0 => ok
#        nLimitDate : Limit program date (remove all programs ending before the given date
#            => = 0  : No clean up made
#               = -1 : Use current UTC time to do the clean up
#               > 0 : Do the clean up with the given date
#        """
#        return self.server.StartEPGGrab(nDeviceID,nGrabDurationMilliseconds, nLimitDate)
#
#    def StopEPGGrab(self, nDeviceID):
#        """
#        result[0] == 0 => ok
#        """
#        return self.server.StopEPGGrab(nDeviceID)
#
#    def EPG_GetFavoritePrograms(self, nStartTime=0, nStopTime=0, strLanguage="", nFormat=0, nFavoriteSetID=-1, nFavoriteID=-1):
#        """
#        IN :
#           0 : Start time (system seconds since 1st January 1970)
#           1 : Stop time (system seconds since 1st January 1970)
#           2 : Language (if "" => All available languages are returned)
#           3 : Format (0:Simple, 1:Detailed)
#        Result:
#           if result[0] == 0 => ok
#           result[1] = array of Programs
#              program[0] = Program ID
#              program[1] = Service ID
#              program[2] = Start time
#              program[3] = Stop time
#              program[4] = Array of program details
#                  ProgramDetails[0] = Language
#                  ProgramDetails[1] = Title
#                  ProgramDetails[2] = ShortDescription
#                  ProgramDetails[3] = Description
#                  ProgramDetails[4] = Minimum age
#                  ProgramDetails[5] = Array of program detail items (if Format = 1)
#                  ProgramDetailItem[0] = Title
#                  ProgramDetailItem[1] = Text
#        """
#        return self.server.EPG.GetFavoritePrograms(nStartTime, nStopTime, strLanguage, nFormat, nFavoriteSetID, nFavoriteID)
#
#    def EPG_GetServicePrograms(self, nServiceID, nStartTime=0, nStopTime=0, strLanguage="", nFormat=0):
#        """
#        IN :
#           0 : Start time (system seconds since 1st January 1970)
#           1 : Stop time (system seconds since 1st January 1970)
#           2 : Language (if "" => All available languages are returned)
#           3 : Format (0:Simple, 1:Detailed)
#        Result:
#           if result[0] == 0 => ok
#           result[1] = array of Programs
#              program[0] = Program ID
#              program[1] = Service ID
#              program[2] = Start time
#              program[3] = Stop time
#              program[4] = Array of program details
#                  ProgramDetails[0] = Language
#                  ProgramDetails[1] = Title
#                  ProgramDetails[2] = ShortDescription
#                  ProgramDetails[3] = Description
#                  ProgramDetails[4] = Minimum age
#                  ProgramDetails[5] = Array of program detail items (if Format = 1)
#                  ProgramDetailItem[0] = Title
#                  ProgramDetailItem[1] = Text
#        """
#        return self.server.EPG.GetServicePrograms(nStartTime, nStopTime, strLanguage, nFormat, float(nServiceID))
class Recording:
    def __init__(self, arg):
        """
        arg[0] = RecordingID
        arg[1] = DeviceID
        arg[2] = Service ID (DatabaseID)
        arg[3] = Name
        arg[4] = RecordingType
              => 0 : Timeshift (live / recording)
              => 1 : Normal Record
              => 2 : Normal live
        arg[5] = Parameters
        arg[6] = is recording ? (1 = yes)
        arg[7] = is in live ? (1 = yes)
        arg[8] = Detailed recording type
                1 : timeshift live
                2 : normal live
                3 : normal record
                4 : timeshift record
        """
        self.id = arg[0]
        self.deviceid = arg[1]
        self.serviceid = arg[2]
        self.name = arg[3]
        self.type = arg[4]
        self.parameters = arg[5]
        if arg[6] == 1:
            self.isrecording = True
        else:
            self.isrecording = False
        self.parameters = arg[5]
        if arg[7] == 1:
            self.isinlive = True
        else:
            self.isinlive = False
        self.detailedType = arg[8]

    def __str__(self):
        strType = "Unknown"
        if self.type == 0:
            strType = "Timeshift (live / recording)"
        elif self.type == 1:
            strType = "Normal Record"
        elif self.type == 2:
            strType = "Normal live"

        strDetailedType = "Unknown"
        if self.detailedType == 1:
            strDetailedType = "timeshift live"
        elif self.detailedType == 2:
            strDetailedType = "normal live"
        elif self.detailedType == 3:
            strDetailedType = "normal record"
        elif self.detailedType == 4:
            strDetailedType = "timeshift record"

        strRecording = "No"
        if self.isrecording:
            strRecording = "Yes"
        strInLive = "No"
        if self.isinlive:
            strInLive = "Yes"
        return "RecID = %d, " \
               "DeviceID = %d, " \
               "ServiceID = %s, " \
               "Name = %s, " \
               "Type = %s, " \
               "Params = %s, " \
               "Recording ? = %s, " \
               "In live ? = %s, " \
               "RecordingType = %s" % \
               (self.id, self.deviceid, str(self.serviceid), self.name, \
            strType, self.parameters, strRecording, strInLive, strDetailedType)

#class Service:
#    def __init__(self, arg, nFormat):
#        """
#        if nFormat == 0
#           arg[0] = Service ID
#           arg[1] = Transponder ID
#           arg[2] = Service Name
#           arg[3] = Service Type
#           arg[4] = Protected (0 = No, 1 = yes)
#        if Format == 1 (Semi-detailed format):
#           arg[0] = ServiceID (i4)
#           arg[1] = TransponderID (i4)
#           arg[2] = ServiceName (string)
#           arg[3] = ProviderName (string)
#           arg[4] = Properties (string)
#           arg[5] = DVBServiceID (i4)
#           arg[6] = NetworkID (i4)
#           arg[7] = TransportStreamID (i4)
#           arg[8] = Protected (0 = No, 1 = yes)
#        if Format == 2 (Detailed format):
#           arg[0] = ServiceID (i4)
#           arg[1] = TransponderID (i4)
#           arg[2] = ServiceName (string)
#           arg[3] = ProviderName (string)
#           arg[4] = ServiceType (i4)
#                    => 0 : Unknown
#                    => 1 : Radio
#                    => 2 : TV
#                    => 3 : Data
#           arg[5] = VideoPID (i4)
#           arg[6] = PCRPID (i4)
#           arg[7] = PMTPID (i4)
#           arg[8] = TeletextPID (i4)
#           arg[9] = Scrambled (i4) (0 : Not scrambled, 1 : scrambled)
#           arg[10] = Protected (0 = No, 1 = yes)
#           arg[11] = Array of AudioStreams
#                {
#                    PID (i4)
#                    Type (i4)
#                        => 0 : Unknown
#                        => 1 : MPEG2
#                        => 2 : AC3
#                    Language (string)
#                }
#        Service Properties:
#        # SID:NID:TID:VPID:PCRPID:AudioStreams:PMTPID:TPID:SBPID
#        # Each numeric value is specified in decimal
#        # Each of those fields can be empty (0 values)
#        # SID : Service ID
#        # NID : Network ID
#        # TID : Transport Stream ID
#        # VPID : Video PID
#        # PCRPID : PCR PID
#        # AudioStreams : List of Audio stream strings separated by ',' character (see CDVBAudioStream class)
#        # PMTPID: PMT PID
#        # TPID : Teletext PID
#        # SBPID: Subtitling PID
#        """
#        self.audiostreams = []
#        self.provider = ""
#        self.properties = ""
#        self.dvbserviceid = 0
#        self.networkid = 0
#        self.transportstreamid = 0
#        self.type = 0
#        self.video_pid = 8192
#        self.pcr_pid = 8192
#        self.pmt_pid = 8192
#        self.teletext_pid = 8192
#        self.subtitling_pid = 8192
#        self.scrambled = False
#        if nFormat == 0:
#           self.id = int(arg[0])
#           self.transponderid = arg[1]
#           self.name = arg[2]
#           self.type = arg[3]
#           if arg[4] == 0:
#            self.protected = False
#           else:
#            self.protected = True
#        elif nFormat == 1:
#           self.id = int(arg[0])
#           self.transponderid = arg[1]
#           self.name = arg[2]
#           self.provider = arg[3]
#           self.properties = arg[4]
#           self.dvbserviceid = arg[5]
#           self.networkid = arg[6]
#           self.transportstreamid = arg[7]
#           if arg[8] == 0:
#            self.protected = False
#           else:
#            self.protected = True
#        elif nFormat == 2:
#           self.id = int(arg[0])
#           self.transponderid = arg[1]
#           self.name = arg[2]
#           self.provider = arg[3]
#           self.type = arg[4]
#           self.video_pid = arg[5]
#           self.pcr_pid = arg[6]
#           self.pmt_pid = arg[7]
#           self.teletext_pid = arg[8]
#           if arg[9] == 0:
#              self.scrambled = False
#           else:
#              self.scrambled = True
#           if arg[10] == 0:
#            self.protected = False
#           else:
#            self.protected = True
#           for audiostream in arg[11]:
#              self.audiostreams.append({ 'pid' : audiostream[0], 'type' : audiostream[1], 'lang' : audiostream[2] })
#
#
#    def __str__(self):
#        return "ID = %d, " \
#               "Name = %s, " \
#               "Provider = %s, " \
#               "TP ID = %d, " \
#               "Type = %d, " \
#               "PMT PID = %d, " \
#               "Video PID = %d, " \
#               "PCR PID = %d, " \
#               "Teletext PID = %d, " \
#               "Subtitling PID = %d, " \
#               "Scrambled = %d, " \
#               "Protected = %d, " \
#               "Audio = %s" % \
#               (int(self.id), self.name, self.provider, self.transponderid, self.type, self.pmt_pid, self.video_pid, self.pcr_pid, self.teletext_pid, self.subtitling_pid, self.scrambled, self.protected, self.audiostreams)
class Service:
    def __init__(self, arg, nFormat):
        """
        if nFormat == 0
           arg[0] = Service ID
           arg[1] = Transponder ID
           arg[2] = Service Name
           arg[3] = Service Type
           arg[4] = Protected (0 = No, 1 = yes)
        if Format == 1 (Semi-detailed format):
           arg[0] = ServiceID (i4)
           arg[1] = TransponderID (i4)
           arg[2] = ServiceName (string)
           arg[3] = ProviderName (string)
           arg[4] = Properties (string)
           arg[5] = DVBServiceID (i4)
           arg[6] = NetworkID (i4)
           arg[7] = TransportStreamID (i4)
           arg[8] = Protected (0 = No, 1 = yes)
        if Format == 2 (Detailed format):
           arg[0] = ServiceID (i4)
           arg[1] = TransponderID (i4)
           arg[2] = ServiceName (string)
           arg[3] = ProviderName (string)
           arg[4] = ServiceType (i4)
                    => 0 : Unknown
                    => 1 : Radio
                    => 2 : TV
                    => 3 : Data
           arg[5] = VideoPID (i4)
           arg[6] = PCRPID (i4)
           arg[7] = PMTPID (i4)
           arg[8] = TeletextPID (i4)
           arg[9] = Scrambled (i4) (0 : Not scrambled, 1 : scrambled)
           arg[10] = Protected (0 = No, 1 = yes)
           arg[11] = Array of AudioStreams
                {
                    PID (i4)
                    Type (i4)
                        => 0 : Unknown
                        => 1 : MPEG2
                        => 2 : AC3
                    Language (string)
                }
        Service Properties:
        # SID:NID:TID:VPID:PCRPID:AudioStreams:PMTPID:TPID:SBPID
        # Each numeric value is specified in decimal
        # Each of those fields can be empty (0 values)
        # SID : Service ID
        # NID : Network ID
        # TID : Transport Stream ID
        # VPID : Video PID
        # PCRPID : PCR PID
        # AudioStreams : List of Audio stream strings separated by ',' character (see CDVBAudioStream class)
        # PMTPID: PMT PID
        # TPID : Teletext PID
        # SBPID: Subtitling PID
        """
        self.audiostreams = []
        self.provider = ""
        self.properties = ""
        self.dvbserviceid = 0
        self.networkid = 0
        self.transportstreamid = 0
        self.type = 0
        self.video_pid = 8192
        self.pcr_pid = 8192
        self.pmt_pid = 8192
        self.teletext_pid = 8192
        self.subtitling_pid = 8192
        self.scrambled = False
        if nFormat == 0:
           self.id = int(arg[0])
           self.transponderid = arg[1]
           self.name = arg[2]
           self.type = arg[3]
           if arg[4] == 0:
            self.protected = False
           else:
            self.protected = True
        elif nFormat == 1:
           self.id = int(arg[0])
           self.transponderid = arg[1]
           self.name = arg[2]
           self.provider = arg[3]
           self.properties = arg[4]
           self.dvbserviceid = arg[5]
           self.networkid = arg[6]
           self.transportstreamid = arg[7]
           if arg[8] == 0:
            self.protected = False
           else:
            self.protected = True
        elif nFormat == 2:
           self.id = int(arg[0])
           self.transponderid = int(arg[1])
           self.name = str(arg[2])
           self.provider = str(arg[3])
           #self.name = str(arg[2].encode('utf8'))
           #self.provider = str(arg[3].encode('utf8'))
           self.type = int(arg[4])
           self.video_pid = int(arg[5])
           self.pcr_pid = int(arg[6])
           self.pmt_pid = int(arg[7])
           self.teletext_pid = int(arg[8])
           if arg[9] == 0:
              self.scrambled = False
           else:
              self.scrambled = True
           if arg[10] == 0:
            self.protected = False
           else:
            self.protected = True
           for audiostream in arg[11]:
              self.audiostreams.append({ 'pid' : int(audiostream[0]), 'type' : int(audiostream[1]), 'lang' : str(audiostream[2].encode('utf8')) })




    def __str__(self):
        return "ID = %d, " \
               "Name = %s, " \
               "Provider = %s, " \
               "TP ID = %d, " \
               "Type = %d, " \
               "PMT PID = %d, " \
               "Video PID = %d, " \
               "PCR PID = %d, " \
               "Teletext PID = %d, " \
               "Subtitling PID = %d, " \
               "Scrambled = %d, " \
               "Protected = %d, " \
               "Audio = %s" % \
               (int(self.id), self.name, self.provider, self.transponderid, self.type, self.pmt_pid, self.video_pid, self.pcr_pid, self.teletext_pid, self.subtitling_pid, self.scrambled, self.protected, str(self.audiostreams))

class Device:
    def __init__(self, arg):
        """
        arg[0] = DeviceID
        arg[1] = Name
        arg[2] = Type (same as nDeviceType)
            => 1 : DVB-T
            => 2 : DVB-S
            => 4 : DVB-C
            => 8 : ATSC
        arg[3] = Position
        arg[4] = Frontend device name (ex: /dev/dvb/adapter0/frontend0)
        arg[5] = Demux device name
        arg[6] = Primary Device ID
        arg[7] = Priority
        """
        self.id = arg[0]
        self.name = arg[1]
        self.type = arg[2]
        self.position = arg[3]
        self.frontend = arg[4]
        self.demux = arg[5]
        self.primary_deviceid = arg[6]
        self.priority = arg[7]

    def __str__(self):
        return "ID = %d, " \
               "Name = %s, " \
               "Type = %d, " \
               "Position = %d, " \
               "Frontend = %s, " \
               "Demux = %s, " \
               "Primary DeviceID = %d, " \
               "Priority = %d" % \
               (self.id, self.name, self.type, self.position, self.frontend, self.demux, self.primary_deviceid, self.priority)

class ProgramDescription:
    def __init__(self, arg, nFormat=0):
        """
        programDescription[0] = Language
        programDescription[1] = Title
        programDescription[2] = Short description
        programDescription[3] = Description
        programDescription[4] = Minimum age
        
        if nFormat==1:
        programDescription[5] = Array of Items
           Item[0] = Title
           Item[1] = Text
        """
        self.language = arg[0]
        self.title = arg[1]
        self.short_description = arg[2]
        self.description = arg[3]
        self.minimum_age = arg[4]
        self.details = []
        if nFormat == 1:
            for detail in arg[5]:
                self.details.append({ 'title' : detail[0], 'text' : detail[1] })

    def __str__(self):
        return "Lang = %s, " \
               "Title = %s, " \
               "Short description = %s, " \
               "Description = %s, " \
               "Minimum Age = %d, " \
               "Details = %s" \
               % \
               ( \
                   self.language, \
                   self.title, \
                   self.short_description, \
                   self.description, \
                   self.minimum_age, \
                   self.details \
                   )
        
class Program:
    def __init__(self, arg, nFormat=0):
        """
        arg[0] = id
        arg[1] = DB service id
        arg[2] = Start time
        arg[3] = Stop time
        arg[4] = Array of program description
        
        programDescription[0] = Language
        programDescription[1] = Title
        programDescription[2] = Short description
        programDescription[3] = Description
        programDescription[4] = Minimum age
        
        if nFormat==1:
        programDescription[5] = Array of Items
           Item[0] = Title
           Item[1] = Text
        """
        self.id = arg[0]
        self.serviceid = arg[1]
        self.start_time = arg[2]
        self.stop_time = arg[3]
        self.program_descriptions = {}
        self.program_description = None
        i = 0
        for args in arg[4]:
            self.program_descriptions[args[0]] = ProgramDescription(args, nFormat)
            if i == 0:
                self.program_description = self.program_descriptions[args[0]]
            i = i + 1

    def __str__(self):
        return "ID = %d, " \
               "Service ID = %d, " \
               "StartTime = %d, " \
               "StopTime = %d, " \
               "__duration = %d, " \
               "program description = %s" % \
               (int(self.id), int(self.serviceid), self.start_time, self.stop_time, self.stop_time - self.start_time, self.program_description)
# 0 : ID
# 1 : NAME
# 2 : ANTENNA_ID
# 3 : TYPE
class TransponderSet:
    def __init__(self, fields):
        self.id = fields[0]
        self.name = fields[1]
        self.type = fields[2]
    def __str__(self):
        return 'TransponderSet : ID = %d, name = "%s", type = %d' % (self.id, self.name, self.type)
# 0 : ID
# 1 : NAME
# 2 : PROPERTIES
# 3 : TRANSPONDER_SET_ID
class Transponder:
        def __init__(self, fields):
            self.id = fields[0]
            self.name =fields[1]
            self.properties = fields[2]
            self.transponderset_id = fields[3]

        def __str__(self):
                return 'Transponder : ID = %d, name = "%s", properties = "%s", transponderset_id = %d' % (self.id, self.name, self.properties, self.transponderset_id)

# 0 : ID
# 1 : NAME
# 2 : SWITCH_TYPE (0 : None, 1 : ToneBurst, 2 : DiSEqC 1.0, 3 : DiSEqC 1.2 (motorized))
# 3 : SWITCH_POSITION
# 4 : LNB_POWER (0 : OFF, 1 : ON)
# 5 : LNB_TYPE_ID
class Antenna:
        def __init__(self, fields):
            self.id = fields[0]
            self.name = fields[1]
            self.switchtype = fields[2]
            self.switchposition = fields[3]
            self.lnbpower = fields[4]
            self.lnbtype_id = fields[5]
        
        def __str__(self):
                return 'Antenna     : ID = %d, name = "%s", switchtype = %d, switchpos = %d, lnbpower = %d, lnb_type_id = %d' % (self.id, self.name, self.switchtype, self.switchposition, self.lnbpower, self.lnbtype_id)

# 0 : ID
# 1 : NAME
# 2 : READ_ONLY
# 3 : FRENQUENCY_LOW
# 4 : FRENQUENCY_HIGH
# 5 : FRENQUENCY_SWITCH
# 6 : 22KH_TONE
class LNBType:
        def __init__(self, fields):
            self.id = fields[0]
            self.name = fields[1]
            self.read_only = fields[2]
            self.freq_low = fields[3]
            self.freq_high = fields[4]
            self.freq_switch = fields[5]
            self.tone = fields[6]

        def __str__(self):
                return 'LNBType : ID = %d, name = "%s, read_only = %d, freq_low = %d, freq_high = %d, freq_switch = %d' \
        % (self.id, self.name, self.read_only, self.freq_low, self.freq_high, self.freq_switch)

def trace_service(services, nFormat):
    if services == None:
        print "ERROR : service == None !"
        return

    if nFormat == 0:
        for service in services:
            print "Service: '%s'" % service[2]
            print "  ID        = ", service[0]
            print "  TPID      = ", service[1]
            print "  Name      = ", service[2]
            print "  Type      = ", service[3]
            print "  Protected = ", service[4]
        return

    if nFormat == 1:
        for service in services:
            print "Service: '%s'" % service[2]
            print "  ID        = ", service[0]
            print "  TPID      = ", service[1]
            print "  Name      = ", service[2]
            print "  Provider  = ", service[3]
            print "  Properties= ", service[4]
            print "  ServiceID = ", service[5]
            print "  NetworkID = ", service[6]
            print "  TSID      = ", service[7]
            print "  Protected = ", service[8]
        return
    
    if nFormat == 2:
        for service in services:
            print "Service: '%s'" % service[2]
            print "  ID            = ", service[0]
            print "  TPID          = ", service[1]
            print "  Name          = ", service[2]
            print "  Provider      = ", service[3]
            print "  Type          = ", service[4]
            print "  Video PID     = ", service[5]
            print "  PCR PID       = ", service[6]
            print "  PMT PID       = ", service[7]
            print "  TeletextPID   = ", service[8]
            print "  SubtitlingPID = ", service[9]
            print "  Scrambled     = ", service[10]
            print "  Protected     = ", service[11]
            for audiostream in service[12]:
                print "  AudioStream:"
                print "      PID      = ", audiostream[0]
                print "      Type     = ", audiostream[1]
                print "      Language = ", audiostream[2]
        return
     


class CallbackServer(object):
    def __init__(self):
        self.callbackList = []
    def register(self, callback):
        self.callbackList.append(callback)
    def unregister(self, callback):
        if callback in self.callbackList:
            self.callbackList.remove(callback)
            return True
        else:
            return False
    def notify(self, *args, **kargs):
        for callback in self.callbackList:
            callback(*args, **kargs)


#def errorHandler(type,message):
#    print 'Error signal: type:',type,'message: "'+message+'"'
#
#def eventHandler(type,message):
#    print 'Event signal: type:',type,'message: "'+message+'"'
#
#def EPGHandler(EPG):
#    print 'EPG signal:',EPG 
#
#def ScanEventHandler(nDeviceID, nEventID):
#    if nEventID == 1:
#        strEvent = "STARTED"
#    elif nEventID == 2:
#        strEvent = "FINISHED"
#    elif nEventID == 3:
#        strEvent = "COMMIT_COMPLETED"
#    print "Device %d : Scan %s !" % (nDeviceID, strEvent)
#
#def ScanServiceFoundHandler(nDeviceID, nServiceID, strServiceName):
#    print "Scan on device %d : Found service '%s' (ID = %s) !" % (nDeviceID, strServiceName, nServiceID)
#
##def ServiceUpdateHandler(nUpdateType, nServiceID, strServiceName, nLogicalChannelNumber, nChannelType):
#def ServiceUpdateHandler(nUpdateType, Service):
#    nServiceID = Service[0]
#    strServiceName = Service[1]
#    nLogicalChannelNumber = Service[2]
#    nChannelType = Service[3]
#    strChannelDescription = "ServiceID = %s, Name = '%s', LCN = %d, Type = %d" % (nServiceID, strServiceName, nLogicalChannelNumber, nChannelType)
#    strUpdateType = "UNKNOWN"
#    if nUpdateType == 0:
#       strUpdateType  = "ADD"
#    if nUpdateType == 1:
#       strUpdateType  = "UPDATE"
#    if nUpdateType == 2:
#       strUpdateType  = "REMOVAL"
#    print "ServiceUpdate : %s : %s" % (strUpdateType, strChannelDescription)
